from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from tools import KeepAspectScale
from selection_box import SelectionBox
import cv2 as cv



class PlaybackWindow(QGraphicsView):
    def __init__(self, parent):
        super().__init__(parent)
        #
        self.setStyleSheet(u"broder: none")
        self.setBackgroundBrush(QColor(10, 10, 10, 200))
        self.setHorizontalScrollBarPolicy(
            Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)

        #
        self.setScene(QGraphicsScene())
        self.playbackItem = QGraphicsPixmapItem()
        self.playbackItem.setPos(0, 0)
        self.scene().addItem(self.playbackItem)

        self.frame = None               # 要播放的视频帧
        self.curViewSize = None         # 存放窗口的当前大小
        self.curPlaySize = None         # 存放视频帧当前的实际播放大小
        self.oldPlaySize = None         # 存放窗口大小改变之前的视频帧播放大小
        self.scaleRatio = None          # 存放视频帧原始大小和实际播放大小之间的缩放比例
        self.scaleBy = None             # 粗放是基于宽度，还是高度进行的缩放

    #
    def updatePlayBackItem(self):
        fh, fw = self.frame.shape
        ww = self.curViewSize.width()
        wh = self.curViewSize.height()
        scaledSize, self.scaleBy = KeepAspectScale(fw, fh, ww, wh)

        self.curPlaySize = QSizeF(*scaledSize)
        self.playbackItem.setPos(
            QPointF((ww - scaledSize[0])/2, (wh - scaledSize[1])/2))

    #
    def updateScaleRatio(self):
        match self.scaleBy:
            case "width":
                self.scaleRatio = self.curPlaySize.width() / self.oldPlaySize.width()

            case "height":
                self.scaleRatio = self.curPlaySize.height() / self.oldPlaySize.height()

    #
    def playFrame(self, frame):
        needUpdatePlaybackItem = False

        if (self.frame is None or frame.shape != self.frame.shape):
            needUpdatePlaybackItem = True

        self.frame = frame

        if needUpdatePlaybackItem:
            self.updatePlayBackItem()

        self.displayFrame()

    #
    def displayFrame(self):
        frame = cv.cvtColor(cv.resize(self.frame, (int(self.curPlaySize.width()), int(
            self.curPlaySize.height()))), cv.COLOR_GRAY2RGB)
        height, width, depth = frame.shape
        self.playbackItem.setPixmap(QPixmap.fromImage(
            QImage(frame.data, width, height, width*depth, QImage.Format_RGB888)))

    #
    def resizeEvent(self, event):
        self.oldPlaySize = self.curPlaySize
        self.curViewSize = event.size()

        self.setSceneRect(QRectF(QPointF(0, 0), self.curViewSize))

        if self.frame is None:
            return
        #
        playbackItemOldPos = self.playbackItem.pos()
        #
        self.updatePlayBackItem()
        #
        playbackItemNewPos = self.playbackItem.pos()
        #
        self.displayFrame()

        # 处理内部的选择框
        self.updateScaleRatio()        
        for item in self.scene().items():
            if isinstance(item, SelectionBox):
                x = item.getX() - playbackItemOldPos.x()
                y = item.getY() - playbackItemOldPos.y()
                w = item.getWidth()
                h = item.getHeight()
                
                item.setLimit(QRectF(playbackItemNewPos, self.curPlaySize))
                item.setState(
                    QPointF(x * self.scaleRatio + playbackItemNewPos.x(), y * self.scaleRatio + playbackItemNewPos.y()),
                    QSizeF(w * self.scaleRatio, h * self.scaleRatio)
                )

    def mouseReleaseEvent(self, event):
        logging.info("鼠标松开了！")
        return super().mouseReleaseEvent(event)
    
    def refreshSelections(self):
        return 
    
    
    def addNewSelection(self, id):
        if self.frame is None:
            return
        
        self.scene().addItem(
            SelectionBox(
                id=id, 
                pos=self.playbackItem.pos(), 
                size=self.curPlaySize,
                limitRect=QRectF(self.playbackItem.pos(), self.curPlaySize)
            )
        )
        
    def getSelection(self, id):
        for item in self.scene().items():
            if isinstance(item, SelectionBox) and item.id == id:
                return item
        return None
    
    def getSelectionSize(self, id):
        if self.frame is None:
            return None
        
        selection = self.getSelection(id)
        height, width  = self.frame.shape
        
        return QSizeF(
            width * selection.getWidth() / self.curPlaySize.width(),
            height * selection.getHeight() / self.curPlaySize.height(),
        )
        
    def getSelectionPos(self, id):
        if self.frame is None:
            return None
        selection = self.getSelection(id)
        height, width  = self.frame.shape
        
        return QPointF(
            (selection.getX() - self.playbackItem.pos().x()) * width / self.curPlaySize.width(),
            (selection.getY() - self.playbackItem.pos().y()) * width / self.curPlaySize.height(),
        )
        
    
    def setSelectionSize(self, id, size):
        if self.frame is None:
            return None
        
        selection = self.getSelection(id).setSize(size)
       
       
       

# 测试组件是否正常工作↓
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.video = None
        self.resize(500, 400)
        
        #################################
        
        # 第一行
        topHboxLayout = QHBoxLayout()        
        selectVideoButton = QPushButton("选择文件", self)
        selectVideoButton.clicked.connect(self.selectVideo)
        topHboxLayout.addWidget(selectVideoButton)        
        selectedVideoFullPath = QLabel("显示文件的绝对路径", self)
        topHboxLayout.addWidget(selectedVideoFullPath)
        addSelectionButton = QPushButton("增加选择框", self)
        addSelectionButton.clicked.connect(self.addSelect)
        topHboxLayout.addWidget(addSelectionButton)
        
        addSelectionButton1 = QPushButton("打印尺寸", self)
        addSelectionButton1.clicked.connect(self.getsize)
        topHboxLayout.addWidget(addSelectionButton1)
        
        addSelectionButton2 = QPushButton("打印位置", self)
        addSelectionButton2.clicked.connect(self.getpos)
        topHboxLayout.addWidget(addSelectionButton2)
        
        self.videoPreviewWindow = PlaybackWindow(parent=self)
        
        # 总体布局
        mainLayout = QVBoxLayout()
        mainLayout.addLayout(topHboxLayout)
        mainLayout.addWidget(self.videoPreviewWindow)
        
        self.setLayout(mainLayout)
        
    def selectVideo(self):
        file = QFileDialog.getOpenFileName(self, "选择视频文件", "/", "Video File(*.avi *.mp4)")
        
        if file[0] == "":                        
            return
        
        self.video = cv.VideoCapture(file[0])
        
        if not self.video.isOpened():
            QMessageBox.warning(self, "FBI WARNING", f"指定路径：${file[0]} 下的文件读取失败", QMessageBox.ok)
            self.video = None
            return
        
        rval, frame = self.video.read()
        frame = cv.cvtColor(frame, cv.COLOR_BGR2GRAY)
        
        self.videoPreviewWindow.playFrame(frame)
        # 将图像传递到label里进行预览    
    
    def addSelect(self):
        self.videoPreviewWindow.addNewSelection(id="SelectionBox") 
        
    def getsize(self):
        logging.info(self.videoPreviewWindow.getSelectionSize("SelectionBox"))

    def getpos(self):
        logging.info(self.videoPreviewWindow.getSelectionPos("SelectionBox"))
        

import sys

if __name__ == "__main__":
    app = QApplication.instance()
    if app is None:
        app = QApplication(sys.argv)

    window = MainWindow()
    window.show()
    sys.exit(app.exec())


